{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "3d358946-f6db-4437-b816-604af2bd6507",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "# 获取Deepseek API Key\n",
    "\n",
    "import os\n",
    "\n",
    "api_key = os.getenv('DEEPSEEK_API_KEY')\n",
    "if api_key is None:\n",
    "    api_key = ''\n",
    "print(api_key)\n",
    "\n",
    "# 设置清华代理\n",
    "\n",
    "os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "45c6e979-4aa5-4d3b-a89a-d03f397b7e9e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "417\n"
     ]
    }
   ],
   "source": [
    "# 准备知识数据\n",
    "\n",
    "text_lines = []\n",
    "\n",
    "with open('mfd.md', 'r') as file:\n",
    "    text_line = file.read()\n",
    "text_lines += text_line.split('\\n\\n')\n",
    "\n",
    "print(len(text_lines))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "4657c7d9-e758-46f4-aab2-e1c36dfc19ae",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/miniconda3/envs/deepseek/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "768\n"
     ]
    }
   ],
   "source": [
    "# 准备Embedding模型\n",
    "\n",
    "from pymilvus import model as milvus_model\n",
    "\n",
    "embedding_model = milvus_model.DefaultEmbeddingFunction()\n",
    "test_embdding = embedding_model.encode_queries(['This is a test'])[0]\n",
    "embedding_dim = len(test_embdding)\n",
    "\n",
    "print(embedding_dim)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "2bfd315b-4239-4c01-b646-aedcb37c99ad",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Creating embeddings: 100%|██████████| 417/417 [00:00<00:00, 478267.64it/s]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'insert_count': 417, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416], 'cost': 0}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 将知识数据加载至Milvus数据库\n",
    "\n",
    "from pymilvus import MilvusClient\n",
    "from tqdm import tqdm\n",
    "\n",
    "my_collection = 'mfd_rag_collection'\n",
    "\n",
    "milvus_client = MilvusClient(uri='./milvus_demo2.db')\n",
    "\n",
    "if milvus_client.has_collection(my_collection):\n",
    "    milvus_client.drop_collection(my_collection)\n",
    "\n",
    "milvus_client.create_collection(\n",
    "    collection_name=my_collection,\n",
    "    dimension=embedding_dim,\n",
    "    metric_type='IP',\n",
    "    consistency_level='Strong'\n",
    ")\n",
    "\n",
    "data = []\n",
    "\n",
    "doc_embeddings = embedding_model.encode_documents(text_lines)\n",
    "for i, line in enumerate(tqdm(text_lines, desc='Creating embeddings')):\n",
    "    data.append({'id':i, 'vector': doc_embeddings[i], 'text': line})\n",
    "\n",
    "milvus_client.insert(collection_name=my_collection, data=data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "546f5734-7a61-4965-9cf7-f93386886a45",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "    [\n",
      "        \"**第三百八十六条** 居住权人有权对居住权的住宅进行维修、养护，但不得改变住宅的用途。\\n居住权人对居住权的住宅享有占有、使用的权利。\",\n",
      "        0.6666156053543091\n",
      "    ],\n",
      "    [\n",
      "        \"**第三百七十六条** 建设用地使用权消灭的，登记机构应当依法办理注销登记。\\n建设用地使用权人应当按照约定向土地所有权人支付出让金。\",\n",
      "        0.6666156053543091\n",
      "    ],\n",
      "    [\n",
      "        \"**第三百五十五条** 用益物权人行使权利，不得损害所有权人的合法权益。\\n用益物权人不得转让、出租、担保其用益物权。法律另有规定或者当事人另有约定的除外。\",\n",
      "        0.6666156053543091\n",
      "    ]\n",
      "]\n",
      "[\n",
      "    [\n",
      "        \"**第三百八十六条** 居住权人有权对居住权的住宅进行维修、养护，但不得改变住宅的用途。\\n居住权人对居住权的住宅享有占有、使用的权利。\",\n",
      "        0.6666156053543091\n",
      "    ],\n",
      "    [\n",
      "        \"**第三百七十六条** 建设用地使用权消灭的，登记机构应当依法办理注销登记。\\n建设用地使用权人应当按照约定向土地所有权人支付出让金。\",\n",
      "        0.6666156053543091\n",
      "    ],\n",
      "    [\n",
      "        \"**第三百五十五条** 用益物权人行使权利，不得损害所有权人的合法权益。\\n用益物权人不得转让、出租、担保其用益物权。法律另有规定或者当事人另有约定的除外。\",\n",
      "        0.6666156053543091\n",
      "    ]\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "# 查询Milvus数据库\n",
    "\n",
    "import json\n",
    "\n",
    "question1 = '登记机构应当履行什么职责？'\n",
    "question2 = '征收的含义是什么？'\n",
    "\n",
    "search_res1 = milvus_client.search(\n",
    "    collection_name=my_collection,\n",
    "    data=embedding_model.encode_queries([question1]),\n",
    "    limit=3,\n",
    "    search_params={'metric_type': 'IP', 'params': {}},\n",
    "    output_fields=['text']\n",
    ")\n",
    "\n",
    "search_res2 = milvus_client.search(\n",
    "    collection_name=my_collection,\n",
    "    data=embedding_model.encode_queries([question2]),\n",
    "    limit=3,\n",
    "    search_params={'metric_type': 'IP', 'params': {}},\n",
    "    output_fields=['text']\n",
    ")\n",
    "\n",
    "retrieved_lines1 = [(res['entity']['text'], res['distance']) for res in search_res1[0]]\n",
    "\n",
    "retrieved_lines2 = [(res['entity']['text'], res['distance']) for res in search_res2[0]]\n",
    "\n",
    "print(json.dumps(retrieved_lines1, indent=4, ensure_ascii=False))\n",
    "print(json.dumps(retrieved_lines2, indent=4, ensure_ascii=False))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "9c9e7c8b-8c7e-4c4d-9c45-945cc5d80192",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 结合Deepseek完成RAG查询\n",
    "\n",
    "from openai import OpenAI\n",
    "\n",
    "deepseek_client = OpenAI(\n",
    "    api_key=api_key,\n",
    "    base_url='https://api.deepseek.com/v1'\n",
    ")\n",
    "\n",
    "SYSTEM_PROMPT = \"\"\"\n",
    "你是一个AI助手，你能够从提供的上下文段落片段中找到问题的答案。\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "dafbbc9d-5219-4165-8b93-2409998f81fa",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "根据《context》中**第三百七十六条**的规定，登记机构应当履行的职责是：在建设用地使用权消灭时，依法办理注销登记。\n"
     ]
    }
   ],
   "source": [
    "# 询问第一个问题\n",
    "\n",
    "context = '\\n'.join([line_with_distance[0] for line_with_distance in retrieved_lines1])\n",
    "\n",
    "USER_PROMPT = f\"\"\"\n",
    "请使用以下用<context>标签括起来的信息片段来回答用<question>标签括起来的问题。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question1}\n",
    "</question>\n",
    "\"\"\"\n",
    "\n",
    "response = deepseek_client.chat.completions.create(\n",
    "    model='deepseek-chat',\n",
    "    messages=[\n",
    "        {'role': 'system', 'content': SYSTEM_PROMPT},\n",
    "        {'role': 'user', 'content': USER_PROMPT}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "edb2b327-abee-420c-918d-ebc89d164879",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "在提供的上下文片段中，并未直接涉及“征收”的定义或相关法律条款。因此，基于当前给定的信息无法回答该问题。若需了解“征收”的法律含义，建议参考《民法典》物权编中关于征收补偿的专门条款（如第二百四十三条等）或其他相关法律法规。\n"
     ]
    }
   ],
   "source": [
    "# 询问第二个问题\n",
    "\n",
    "context = '\\n'.join([line_with_distance[0] for line_with_distance in retrieved_lines2])\n",
    "\n",
    "USER_PROMPT = f\"\"\"\n",
    "请使用以下用<context>标签括起来的信息片段来回答用<question>标签括起来的问题。\n",
    "<context>\n",
    "{context}\n",
    "</context>\n",
    "<question>\n",
    "{question2}\n",
    "</question>\n",
    "\"\"\"\n",
    "\n",
    "response = deepseek_client.chat.completions.create(\n",
    "    model='deepseek-chat',\n",
    "    messages=[\n",
    "        {'role': 'system', 'content': SYSTEM_PROMPT},\n",
    "        {'role': 'user', 'content': USER_PROMPT}\n",
    "    ]\n",
    ")\n",
    "\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e8cebfd-30a4-46cc-8a2b-98765abf3990",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
